namespace HZY.Framework.Aop.Attributes;

/// <summary>
/// MemoryCache 内存缓存
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class MemoryCacheAttribute : AopMoAttribute
{
    /// <summary>
    /// 缓存Key 不填默认是 函数的命名空间.函数名称
    /// </summary>
    /// <value></value>
    public string? CacheKey { get; set; }

    /// <summary>
    /// 缓存时长 (秒) 默认存储 10s 如果0代表永久
    /// </summary>
    /// <value></value>
    public long CacheDuration { get; set; } = 10;

    /// <summary>
    /// 获取缓存Key
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    protected virtual string GetCacheKey(MethodContext context)
    {
        if (!string.IsNullOrWhiteSpace(CacheKey))
        {
            return ParseCacheKey(context);
        }

        var name = context.Method.Name;
        var prefix = context.Method.DeclaringType?.FullName;
        return $"{prefix}.{name}";
    }

    /// <summary>
    /// 解析缓存主键
    /// </summary>
    /// <param name="context">拦截器上下文</param>
    protected virtual string ParseCacheKey(MethodContext context)
    {
        //寻找大括号{} 内的内容
        var replaceParameters = Regex.Matches(CacheKey, @"\{(.+?)\}").Select(m => m.Groups[1].Value).ToList();
        if (replaceParameters.Count <= 0)
        {
            return CacheKey;
        }

        // 获取所有方法参数
        var typeNames = context.Method.GetParameters().Select(t => t.Name).ToList();
        foreach (var replaceParameter in replaceParameters)
        {
            var firstName = replaceParameter.Split(".")[0];
            // 查询括号里的内容  .分割后第一位  能和参数名对的上吗
            if (!typeNames.Contains(firstName))
            {
                continue;
            }

            // 获取这个值对应的索引
            int index = typeNames.FindIndex(tname => tname == firstName);
            // 对内容进行分割
            var names = replaceParameter.Split(".").ToList();

            // 分割后大于长度大于一 说明存在实例内部属性调用
            if (names.Count > 1)
            {
                var replaceName = "{" + replaceParameter + "}";
                // 移除第一位
                names.RemoveAt(0);
                // 递归获取到属性值
                var value = GetParameterValue(context.Arguments[index], names);
                value = value ?? "null";
                CacheKey = CacheKey.Replace(replaceName, value);
            }
            else
            {
                var replaceName = "{" + replaceParameter + "}";
                var value = context.Arguments[index]?.ToString();
                CacheKey = CacheKey.Replace(replaceName, value);
            }
        }

        return CacheKey;
    }

    /// <summary>
    /// 递归获取属性值
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="parameterNames"></param>
    /// <returns></returns>
    protected virtual string? GetParameterValue(object obj, List<string> parameterNames)
    {
        if (parameterNames.Count > 1)
        {
            var name = parameterNames[0];
            parameterNames.RemoveAt(0);

            // 获取属性值
            var propertyInfo = GetPropertyInfo(obj, name);
            if (propertyInfo != null)
            {
                var val = propertyInfo.GetValue(obj);
                if (val is null)
                {
                    return null;
                }

                return GetParameterValue(val, parameterNames);
            }

            return null;
        }
        else if (parameterNames.Count == 1)
        {
            // 获取属性值
            var propertyInfo = GetPropertyInfo(obj, parameterNames[0]);
            // 从对象里获取这个属性
            return propertyInfo?.GetValue(obj)?.ToString();
        }
        else
        {
            return null;
        }
    }

    /// <summary>
    /// 根据属性名称获取实例里的属性
    /// </summary>
    /// <param name="obj">实例</param>
    /// <param name="name">需要的属性名</param>
    /// <returns></returns>
    protected static PropertyInfo? GetPropertyInfo(object obj, string name)
    {
        // 获取所有public属性和实例
        var propertyInfos = obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
        // 找找有没有我们要的
        return propertyInfos.FirstOrDefault(p => p.Name == name);
    }
    
    /// <summary>
    /// 
    /// </summary>
    /// <param name="context"></param>
    public override void OnEntry(MethodContext context)
    {
        GetCache(context);
    }

    public override void OnSuccess(MethodContext context)
    {
        switch (context.ReturnValue)
        {
            case null:
            case ICollection { Count: 0 }:
                return;
            default:
                CreateCache(context, context.ReturnValue);
                break;
        }
    }

    /// <summary>
    /// 获取 MemoryCache 缓存
    /// </summary>
    /// <param name="context"></param>
    protected virtual void GetCache(MethodContext context)
    {
        var key = GetCacheKey(context);
        var memoryCache = GetService<IMemoryCache>(context);

        if (memoryCache is null) return;

        var value = memoryCache.Get(key);

        if (value is null) return;

        context.ReplaceReturnValue(this, value);
    }

    /// <summary>
    /// 创建缓存
    /// </summary>
    /// <param name="methodContext"></param>
    /// <param name="result"></param>
    protected virtual void CreateCache(MethodContext methodContext, object result)
    {
        var memoryCache = GetService<IMemoryCache>(methodContext);
        if (memoryCache is null)
        {
            return;
        }

        var key = GetCacheKey(methodContext);

        if (CacheDuration <= 0)
        {
            memoryCache.Set(key, result);
        }
        else
        {
            memoryCache.Set(key, result, TimeSpan.FromSeconds(CacheDuration));
        }
    }
}